A capture-processing pattern from ICOR for Life

The Larry Directive

A one-line callout that lets a person leave an instruction inside their own capture — before an agent files it — detected by a script, honored by judgement, never guessed at. This page is self-contained: open it straight from disk in any browser, no internet connection or account needed.

01 What it is

Every capture pipeline eventually hits the same problem: the person capturing the note knows exactly how it should be filed, and the agent processing it later has to guess from prose.

The Larry Directive closes that gap with a callout the user types themselves, right inside the capture, addressed to the orchestrator by name regardless of which agent actually executes it:

live — waiting to be honored
📣 Larry: enrich
Combine my notes with the source transcript. Keep my structure; pull the hard numbers out of the transcript.
filed — consumed, never re-fires
🧾 Larry-done: enrich
✅ 2026-09-10 (honored) — merged transcript numbers into the user's outline.

The callout syntax is the safety mechanism. Real prose — typed by the user, or pasted in from a meeting-note tool — essentially never produces > [!larry] verb by coincidence, even though that same prose is full of instruction-shaped language ("let's combine these," "file this under..."). Only an explicit callout the user typed counts. Nothing inferred from body text ever does.

02 Syntax & verbs

One header line, an optional argument after a colon, and the prose underneath.

markdown
> [!larry] enrich
> Combine my notes with the source notes & transcript.
> Keep my structure; pull the hard numbers out of the transcript.
VerbMeaning
enrichMerge the user's notes + an imported summary + transcript into one cohesive record.
holdDo not file yet — an explicit defer that outlasts any in-progress heuristic (recency, a skeletal body) until the user removes it themselves.
splitThis capture covers more than one item — file one note per item.
merge-with: [[note]]Fold into an existing note by wikilink, rather than creating a new one.
file-as: <folder>Override normal routing — e.g. for sensitive material that needs a different home.
askThe user flagged a question or ambiguity — surface it, never guess.

An unrecognized verb is treated as ask and surfaced — never silently dropped. A capture with more than one live directive is never guessed at either; it's reported for the user to resolve by hand.

03 The mechanism

The split that makes this safe to automate: script detection is deterministic and never re-decided; judgement honoring reads and reconciles real content.

  1. script
    find-directive.py <capture> scans for a [!larry] callout and reports its verb, argument, and prose. Prints NONE if there isn't one, or REVIEW — and refuses to pick — if it finds more than one.
  2. judgement
    The agent honors the verb per the table above. enrich, split, and merge-with require actually reading and reconciling content. file-as and ask are closer to mechanical but still route through a read of the capture, never a blind rename.
  3. script
    Once honored — or deliberately deferred, or found unsatisfiable — find-directive.py <capture> --consume <line> --result honored|deferred|unsatisfiable rewrites the callout to [!larry-done] with today's date and the result, so it never fires again.
  4. judgement
    Every directive gets named explicitly in the processing report — honored, deferred, or unsatisfiable. Never half-executed and stamped silently.

04 Hard rules

The four things that keep this mechanism trustworthy enough to run unattended.

05 The kit

Five files. Drop them in, wire three touchpoints (below), done.

Requirements: Obsidian, obviously. The CSS and the detection script have no dependencies. The Templater snippet needs the free Templater community plugin installed — see §06 if you don't have it yet. Running find-directive.py as part of an actual processing routine needs Python 3, but nothing to install — it's stdlib-only.

Obsidian CSS — portable version

Uses only Obsidian's own built-in variables (--text-normal, --text-faint, --background-modifier-border) plus one hardcoded marker-orange accent, so it renders correctly in any theme — light or dark — with no dependency on a custom theme's design tokens.

larry-directive-portable.css
/* Larry directive callouts — portable version.
   Built only on Obsidian's own CSS variables, so it renders
   correctly in any theme, light or dark, with no dependency
   on custom design tokens. One hardcoded accent (marker
   orange) marks a directive as live; it fades to the theme's
   own faint-text color once filed. */

.callout[data-callout="larry"] {
  --callout-color: 217, 103, 14;
  border: 1.5px dashed rgb(217, 103, 14);
  border-radius: 8px;
  background-color: rgba(217, 103, 14, 0.08);
  box-shadow: 0 2px 10px rgba(217, 103, 14, 0.12);
  transform: rotate(-1deg);
  padding: 0.5em 1.1em;
  margin: 1.4em 0.6em;
}
.callout[data-callout="larry"] .callout-title {
  color: rgb(217, 103, 14);
  font-weight: 600;
}
.callout[data-callout="larry"] .callout-title::before {
  content: "📣  ";
  margin-right: 0.15em;
}

.callout[data-callout="larry-done"] {
  border: 1.5px solid var(--background-modifier-border);
  border-radius: 8px;
  background-color: transparent;
  transform: none;
  opacity: 0.82;
  padding: 0.5em 1.1em;
  margin: 1.4em 0.6em;
}
.callout[data-callout="larry-done"] .callout-title {
  color: var(--text-faint);
  font-weight: 600;
}
.callout[data-callout="larry-done"] .callout-title::before {
  content: "🧾  ";
  margin-right: 0.15em;
}
Running the INKLINE theme instead? Use the two tokenized variants below — they lean on INKLINE's own design tokens (--ink-marker-*, --ink-font-hand, etc.) for a closer match to the ICOR for Life original, and won't render correctly without that theme installed.

Obsidian CSS — INKLINE "margin stamp" (bold)

The version actually enabled in the source vault. Breaks the theme's usual flat-callout rule on purpose: a directive is an active instruction, so it gets to look like a sticky note stapled to the page — tilted, dashed, glowing while live; flattened and faded once filed.

larry-directive-margin-stamp.css
.markdown-rendered .callout[data-callout="larry"],
.cm-s-obsidian .callout[data-callout="larry"] {
  --ink-callout-ink: var(--ink-marker-text);
  border-inline-start: none;
  border: 1.5px dashed var(--ink-marker-border);
  border-radius: var(--ink-radius-subtle);
  background-color: var(--ink-marker-bg);
  box-shadow: var(--ink-float-shadow), var(--ink-marker-glow);
  transform: rotate(-1.5deg);
  padding: 0.5em 1.1em;
  margin: 1.4em 0.6em;
}
.markdown-rendered .callout[data-callout="larry"] .callout-title {
  font-family: var(--ink-font-hand);
  font-weight: var(--ink-hand-weight);
  font-size: var(--ink-text-hand-sm);
  letter-spacing: normal;
  text-transform: none;
}
.callout[data-callout="larry"] .callout-title::before {
  content: "📣  ";
  margin-right: 0.15em;
}
.markdown-rendered .callout[data-callout="larry"] .callout-content {
  font-family: var(--ink-font-hand);
  font-weight: var(--ink-hand-weight-note);
  font-size: var(--ink-text-hand);
  line-height: 1.35;
}

.markdown-rendered .callout[data-callout="larry-done"],
.cm-s-obsidian .callout[data-callout="larry-done"] {
  --ink-callout-ink: var(--ink-paper-faint);
  border-inline-start: none;
  border: 1.5px solid var(--ink-hairline-emphasis);
  border-radius: var(--ink-radius-subtle);
  background-color: transparent;
  transform: none;
  opacity: 0.8;
  padding: 0.5em 1.1em;
  margin: 1.4em 0.6em;
}
.markdown-rendered .callout[data-callout="larry-done"] .callout-title {
  font-family: var(--ink-font-hand);
  font-weight: var(--ink-hand-weight-note);
  font-size: var(--ink-text-hand-sm);
  letter-spacing: normal;
  text-transform: none;
}
.callout[data-callout="larry-done"] .callout-title::before {
  content: "🧾  ";
  margin-right: 0.15em;
}

Obsidian CSS — INKLINE "corner tag" (conservative)

Keeps every other INKLINE callout's flat single-thread rendering exactly as-is, and adds one small filled corner tag — a rubber date-stamp reading DIRECTIVE / FILED — so a directive still visually belongs to the callout family at a glance.

larry-directive-corner-tag.css
.markdown-rendered .callout[data-callout="larry"],
.cm-s-obsidian .callout[data-callout="larry"] {
  --ink-callout-ink: var(--ink-marker-text);
  position: relative;
  padding-top: 0.3em;
}
.markdown-rendered .callout[data-callout="larry"]::after {
  content: "DIRECTIVE";
  position: absolute;
  top: -0.6em;
  right: 0;
  font-family: var(--ink-font-mono);
  font-weight: 600;
  font-size: 10px;
  letter-spacing: 0.14em;
  text-transform: uppercase;
  color: var(--ink-on-marker);
  background: var(--ink-marker-fill);
  padding: 0.25em 0.6em;
  border-radius: var(--ink-radius-control);
}
.callout[data-callout="larry"] .callout-title::before {
  content: "📣  ";
  margin-right: 0.2em;
}

.markdown-rendered .callout[data-callout="larry-done"],
.cm-s-obsidian .callout[data-callout="larry-done"] {
  --ink-callout-ink: var(--ink-paper-faint);
  position: relative;
  padding-top: 0.3em;
  opacity: 0.85;
}
.markdown-rendered .callout[data-callout="larry-done"]::after {
  content: "FILED";
  position: absolute;
  top: -0.6em;
  right: 0;
  font-family: var(--ink-font-mono);
  font-weight: 600;
  font-size: 10px;
  letter-spacing: 0.14em;
  text-transform: uppercase;
  color: var(--ink-paper-faint);
  background: transparent;
  border: 1px solid var(--ink-hairline-emphasis);
  padding: 0.2em 0.55em;
  border-radius: var(--ink-radius-control);
}
.callout[data-callout="larry-done"] .callout-title::before {
  content: "🧾  ";
  margin-right: 0.2em;
}

Detection script script

The one piece of real code in the kit — deterministic parsing, so no agent ever re-decides what a directive says. Python 3, no dependencies.

find-directive.py
#!/usr/bin/env python3
"""Find and consume a `> [!larry] <verb>` directive callout inside a
capture. Detecting the callout, its verb, its argument, and its prose
is deterministic - this script IS the source of truth for that, never
a judgement call re-decided by whichever model reads the file.

Usage:
  find-directive.py <note.md>
      Scan-only. Prints each `[!larry]` callout found: its line number,
      verb, argument (text after a `:` on the header line, if any), and
      prose (the callout's continuation lines). Prints NONE if there is
      no directive. Prints REVIEW and refuses to pick one if more than
      one directive callout is found in the same file - never guesses
      which one is live.

  find-directive.py <note.md> --consume <line> --result honored|deferred|unsatisfiable [--note "..."]
      Rewrites the directive callout starting at <line> (as reported by
      a prior scan) from `[!larry]` to `[!larry-done]`, stamped with
      today's date and the result, so it never fires again. Refuses if
      the line at that position is not actually a `[!larry]` callout
      header (the file may have changed since the scan that found it).

Recognized verbs: enrich, hold, split, merge-with, file-as, ask.
An unrecognized verb is reported as such, never silently dropped -
treat it the same as `ask` (surface it, do not guess).
"""
import argparse
import datetime
import re
import sys
from pathlib import Path

KNOWN_VERBS = {"enrich", "hold", "split", "merge-with", "file-as", "ask"}
HEADER_RE = re.compile(r"^>\s*\[!larry\]\s*([a-z-]+)\s*:?\s*(.*)$")
CONT_RE = re.compile(r"^>\s?(.*)$")


def scan(lines):
    """Return a list of dicts: {line (1-based), verb, known, argument, prose}."""
    found = []
    i = 0
    while i < len(lines):
        m = HEADER_RE.match(lines[i])
        if m:
            verb, rest = m.group(1), m.group(2).strip()
            prose = []
            j = i + 1
            while j < len(lines) and lines[j].startswith(">"):
                cm = CONT_RE.match(lines[j])
                text = cm.group(1) if cm else ""
                if text.strip():
                    prose.append(text.strip())
                j += 1
            found.append({
                "line": i + 1, "verb": verb, "known": verb in KNOWN_VERBS,
                "argument": rest, "prose": " ".join(prose),
            })
            i = j
        else:
            i += 1
    return found


def cmd_scan(note):
    lines = note.read_text(encoding="utf-8").splitlines()
    found = scan(lines)
    if not found:
        print("NONE")
        return
    if len(found) > 1:
        where = ", ".join(str(d["line"]) for d in found)
        print(f"REVIEW: {len(found)} directive callouts found (lines {where}) - resolve by hand, do not guess which is live")
        return
    d = found[0]
    tag = "" if d["known"] else " (UNRECOGNIZED VERB - treat as ask)"
    print(f'DIRECTIVE line={d["line"]} verb={d["verb"]}{tag} argument="{d["argument"]}"')
    print("PROSE:")
    print(d["prose"] or "(none)")


def cmd_consume(note, line_no, result, note_text):
    if result not in ("honored", "deferred", "unsatisfiable"):
        sys.exit(f"FAIL --result must be honored, deferred, or unsatisfiable, got {result!r}")
    lines = note.read_text(encoding="utf-8").splitlines(keepends=True)
    if line_no < 1 or line_no > len(lines):
        sys.exit(f"FAIL line {line_no} is out of range for {note}")
    target = lines[line_no - 1]
    m = HEADER_RE.match(target.rstrip("\n"))
    if not m:
        sys.exit(f"FAIL line {line_no} is not a `[!larry]` directive header - the file "
                  f"may have changed since it was scanned; re-scan before consuming")
    verb, rest = m.group(1), m.group(2).strip()
    today = datetime.date.today().isoformat()
    suffix = f" - {note_text.strip()}" if note_text and note_text.strip() else ""
    colon = f": {rest}" if rest else ""
    newline = "\n" if target.endswith("\n") else ""
    lines[line_no - 1] = f"> [!larry-done] {verb}{colon} ✅ {today} ({result}){suffix}{newline}"
    note.write_text("".join(lines), encoding="utf-8")
    print(f"OK consumed line {line_no}: {verb} -> {result} ({today})")


def main():
    ap = argparse.ArgumentParser(description=__doc__, formatter_class=argparse.RawDescriptionHelpFormatter)
    ap.add_argument("note")
    ap.add_argument("--consume", type=int, metavar="LINE")
    ap.add_argument("--result", choices=["honored", "deferred", "unsatisfiable"])
    ap.add_argument("--note", dest="note_text", default="")
    a = ap.parse_args()

    note = Path(a.note).resolve()
    if not note.is_file():
        sys.exit(f"FAIL no such note: {note}")

    if a.consume is not None:
        if not a.result:
            sys.exit("FAIL --consume requires --result")
        cmd_consume(note, a.consume, a.result, a.note_text)
    else:
        if a.result:
            sys.exit("FAIL --result only makes sense with --consume")
        cmd_scan(note)


if __name__ == "__main__":
    main()

Templater insert snippet

One hotkey, pick a verb from a suggester, cursor lands on the prose line. Needs the Templater plugin.

larry-directive.md (Templater)
<%*
// Insert a Larry directive callout. One hotkey -> pick a verb ->
// cursor lands on the prose line.
const directiveVerbs = ["enrich", "hold", "split", "merge-with:", "file-as:", "ask"];
const chosenVerb = await tp.system.suggester(
  directiveVerbs, directiveVerbs, false, "Directive for Larry:"
);
if (!chosenVerb) return;

let verbArgument = "";
let presetProse = "";
if (chosenVerb === "enrich") {
  presetProse = "";
} else if (chosenVerb === "merge-with:") {
  const targetNote = await tp.system.prompt(
    "Fold into which note? (leave blank to pick inline)"
  );
  verbArgument = targetNote ? ` [[${targetNote}]]` : " [[";
} else if (chosenVerb === "file-as:") {
  const destinationFolders = [
    "Sensitive", "Meetings", "Journal", "Contacts/People",
    "Contacts/Companies", "Projects", "Topics", "Assets/Images", "Assets/Documents",
  ];
  const chosenDestination = await tp.system.suggester(
    destinationFolders, destinationFolders, false, "File it as:"
  );
  if (!chosenDestination) return;
  verbArgument = ` ${chosenDestination}`;
}
-%>
> [!larry] <% chosenVerb %><% verbArgument %>
> <% presetProse ? presetProse + " " : "" %><% tp.file.cursor() %>

06 Setting up the Templater hotkey

The template doesn't do anything until Templater knows about it and you've given it a key combo.

  1. Install Templater, if you haven't already: Settings → Community plugins → Browse → search "Templater" → Install → Enable.
  2. Give Templater a templates folder, if it doesn't have one yet: Settings → Templater → "Template folder location" → point it at whatever folder you keep templates in. Create the folder first if it doesn't exist.
  3. Drop the file in: copy larry-directive-templater.md into that folder (rename it to whatever you like — the filename doesn't matter, Templater just needs it inside the templates folder).
  4. Bind a hotkey: Settings → Hotkeys → search "Templater: Insert Template" → click the + next to it → press your chosen combo (something unused, like Cmd/Ctrl+Shift+L for "Larry"). This opens a picker across all your Templater templates each time. If you'd rather skip the picker, Templater also registers one command per template file the moment it's in the folder — search for it by name instead ("Templater: Insert <templatename>") and bind that one directly.
  5. Try it: cursor in any note, fire the hotkey, pick a verb from the suggester. You should land with > [!larry] enrich (or whichever verb) already typed and your cursor on the prose line.

07 Wiring it into your own pipeline

The directive only does anything once your own capture-processing routine checks for it at three points. In ICOR for Life this lives in the SOP that processes an Inbox capture — adapt the same three touchpoints into whatever runs yours.

Report every directive by name in your processing summary — honored, deferred, or unsatisfiable — the same way you'd report anything else that happened during the run. A directive that gets silently folded into a generic "processed 6 items" line defeats the point of leaving one.

08 Implementing this in your own ICOR for Life vault

If your assistant is Claude Code (or any other AI coding agent) working inside your own vault, hand it this prompt with the path to this kit filled in.

prompt.txt
I want to add the "Larry Directive" capture-directive pattern to this
ICOR for Life vault. I've unzipped a share pack to <PATH TO THIS
FOLDER> containing: README.md (the full spec), find-directive.py,
larry-directive-templater.md, larry-directive-portable.css, and two
INKLINE-specific CSS variants.

Please:

1. Read README.md in that folder for the full spec (syntax, verb
   table, mechanism, hard rules) before changing anything.

2. Add a new guideline note under
   06 AI Team/AI Team Knowledge/Guidelines/ (pick the next unused
   GL-### number) capturing the syntax, verb table, mechanism, and
   hard rules from the README, written in this vault's own guideline
   voice and cross-linked from wherever the guideline index lives.

3. Copy find-directive.py into
   06 AI Team/AI Team Knowledge/Scripts/find-directive.py.

4. Copy larry-directive-templater.md into
   06 AI Team/AI Team Knowledge/Templates/Templater/ (or wherever
   Templater templates already live in this vault). Update the
   `destinationFolders` list inside it to match this vault's actual
   room names, not the ICOR for Life defaults baked into the file.

5. Ask me whether I'm running the INKLINE theme. If yes, offer both
   INKLINE CSS variants (margin-stamp / corner-tag) and let me pick;
   if no, use larry-directive-portable.css instead. Either way, drop
   the chosen file into .obsidian/snippets/ and tell me to enable it
   in Settings → Appearance → CSS snippets (you can't toggle that
   setting for me).

6. Walk me through setting up a Templater hotkey for the new template
   (Settings → Templater → confirm template folder → Settings →
   Hotkeys → bind "Templater: Insert Template" or the per-template
   command Templater registers, whichever I prefer) — don't just tell
   me to do it, confirm each step actually landed.

7. Find whatever SOP, guideline, or routine currently governs
   processing my Inbox/captures, and show me exactly where each of
   the three touchpoints (scan before filing, honor per verb, consume
   before archiving) should go in it, before editing that file.

8. Do a dry run: create one throwaway test capture containing a
   `[!larry] enrich` callout, walk it through the updated processing
   routine, confirm it gets consumed to `[!larry-done]` with today's
   date, then delete the test file and report back.

Ask me before overwriting anything that already exists at any of
these paths, and stop and ask if step 2's guideline numbering or
step 7's target file is ambiguous rather than guessing.